<?php
namespace cubox;

use cubox\provider\SQLParam;

class Database{
    protected $config;
    protected static $sqlList = [];
    public function __construct(array $config)
    {
        $this->config = $config;
    }

    public function getConfig():array{
        return $this->config;
    }

    public function query($sql){
        return null;
    }

    public function getInsertId():int{
        return 0;
    }

    public function escapeName($name):string{
        return $name;
    }

    public function escapeValue($value){
        return $value;
    }
    
    public static function getSqlList():array{
        return self::$sqlList;
    }

    public static function getLastSql():string {
        return end(self::$sqlList);
    }

    public function beginTransaction(){
        throw new \Exception('不支持事务');
    }

    public function commit(){
        throw new \Exception('不支持事务');
    }

    public function rollBack(){
        throw new \Exception('不支持事务');
    }


    public function insert($table,$data){
        $sql = 'INSERT INTO '.$this->escapeName($table).' ';

        $name = [];
        $value  = [];

        foreach ($data as $k => $v){
            $name [] = $this->escapeName($k);
            $value [] = $this->escapeValue($v);
        }

        $sql.='('.implode(', ',$name).') VALUES ('.implode(', ',$value).')';
        
        return $this->query($sql);
    }

    public function select($table,SQLParam $sql){
        return $this->query($this->getSelectSql($table,$sql));
    }

    protected function getSelectSql(string $table,SQLParam $sql):string{
        $sqlstr = "SELECT ";

        if ($sql->field){

            $list = [];

            foreach ($sql->field as $field){
                if (strpos($field,'(') || strpos($field,')') || strpos($field,' ') || strpos($field,'.') || $field =='*'  ){
                    $list[] = $field;
                }else{
                    $list[] = $this->escapeName($field);
                }
            }

            $sqlstr .= implode(' , ',$list);
        }else{
            $sqlstr .= '*';
        }
        
        $sqlstr .= " FROM ".$this->escapeName($table);

        if ($sql->where){
            $sqlstr .= ' WHERE '.$this->where($sql->where);
        }

        if ($sql->join){
            
            foreach($sql->join as $join){
                list($type,$table,$on) = $join;
                $sqlstr .= ' '.strtoupper($type).' JOIN '.$this->escapeName($table).' ON '.$on;
            }

        }

        if ($sql->group){
            $sqlstr .=' GROUP BY '.implode(' , ',$sql->group);
        }


        if ($sql->having){
            $sqlstr .=' HAVING '.$this->where($sql->having);
        }

        if ($sql->order){
            $sqlstr .= ' ORDER BY ';

            foreach($sql->order as $key=>$order){
                if ($key!=0) $sqlstr .= ',';
                $sqlstr .= ' '.$this->escapeName($order[0]).' '.$order[1];
            }
        }

        return $sqlstr;
    }

    public function update($table,$data,SQLParam $sql){
        $sqlstr = 'UPDATE '.$this->escapeName($table).' SET ';

        $update = [];
        foreach ($data as $k => $v){
            $update [] =$this->escapeName($k).' = '.$this->escapeValue( $v ).'';
        }

        $sqlstr.= implode(', ',$update);

        if ($sql->where){
            $sqlstr.=' WHERE '.$this->where($sql->where);
        }

        return $this->query($sqlstr);
    }

    public function delete($table,SQLParam $sql){
        $sqlstr = 'DELETE FROM '.$this->escapeName($table);

        if ($sql->where){
            $sqlstr.=' WHERE '.$this->where($sql->where);
        }else{
            throw new \Exception('请设置删除条件');
        }

        return $this->query($sqlstr);
    }

    protected function where(array $wheres):string{
        $whereStr = [];
        
        foreach($wheres as $k=>$v){
            $whereStr[]= $this->condition($v);
        }

        return implode(' AND ',$whereStr);
    }

    protected function condition(array $args){
        $str  = '';
        //组织OR
        if (is_array($args[0])) {
            $or = [];
            foreach ($args[0] as $arg) {
                //([where1,where2,where3])
                if (count($args) == 1 && is_array($arg)) {
                    if (count($arg) == 2) {
                        $or[] = $this->conditionMarker($arg[0], '=', $arg[1]);
                    }

                    if (count($arg) == 3) {
                        $or[] = $this->conditionMarker($arg[0], $arg[1], $arg[2]);
                    }

                    //$or[] = $this->where(...$arg);
                }
                //([field1,field2,field3],arg2,arg3)
                if (count($args) > 1 && is_string($arg)) {

                    if (count($args) == 2) {
                        $or[] = $this->conditionMarker($arg, '=', $args[1]);
                    }

                    if (count($args) == 3) {
                        $or[] = $this->conditionMarker($arg, $args[1], $args[2]);
                    }
                }
            }

            if (count($or) > 0) {
                $str = '(' . implode(' OR ', $or) . ')';
            }
        }

        if (is_string($args[0])) {

            if (count($args) == 1){
                return $args[0];
            }

            if (count($args) == 2) {
                $str = $this->conditionMarker($args[0], '=', $args[1]);
            }

            if (count($args) == 3) {
                $str = $this->conditionMarker($args[0], $args[1], $args[2]);
            }
        }

        return $str;
    }

    protected function conditionMarker($one, $two, $three = '')
    {

        if (strpos('(',$one)===false){
            $one = $this->escapeName($one);
        }
        
        switch (strtolower($two)) {
            case '==':
            case '=':

                switch ($three) {
                    case 'is null':
                    case 'null':
                        $str = $one . ' is NULL';

                        break;

                    case 'not null':
                    case 'is not null':
                        $str = $one . ' is not NULL';
                        break;

                    default:
                        $str = $one . '=' . $this->escapeValue($three);
                         
                        break;
                }

                break;

            case '>':
            case '<>':
            case '>=':
            case '<':
            case '<=':
                $str = $one . $two . $this->escapeValue($three);
                break;

            case 'in':

                if (is_array($three)) {
                    $_three = array();
                    foreach ($three as $key => $v) {
                        $_three[$key] = $this->escapeValue($v);
                    }

                    $str = $one . ' in (' . implode(',', $_three) . ')';
                } else {

                    $str = $one . ' in (' . $three . ')';
                }

                break;

            case 'like':
                $str = $one . ' like ' . $this->escapeValue($three);
                break;
            case 'is':
                //TODO 哎呀，忘记怎么写了
                break;
        }

        return $str;
    }


    public static function configParams():array{
        return [];
    }

    public static function frontTitle($config){
        unset($config['driver']);
        if(isset($config['password'])) unset($config['password']);  
        return implode('-',$config);
    }
}

